#include "i2c.h"
#include "driver_OLED_Font.h"


/********************* 硬件I2C实现 *********************/

/* OLED设备地址 */
#define OLED_ADDRESS 0x78  // 7位地址，对应SA0=0

/**
  * @brief  I2C写数据到OLED
  * @param  pData 数据指针
  * @param  Size 数据大小
  * @param  IsCmd 1=命令，0=数据
  * @retval HAL状态
  */

static void OLED_I2C_Write(uint8_t *pData, uint16_t Size, uint8_t IsCmd)
{
    uint8_t buffer[Size + 1];
    
    // 第一个字节是控制字节
    buffer[0] = IsCmd ? 0x00 : 0x40;
    
    // 复制数据
    for(uint16_t i = 0; i < Size; i++) {
        buffer[i + 1] = pData[i];
    }
    
    HAL_I2C_Master_Transmit(&hi2c1, OLED_ADDRESS, buffer, Size + 1, HAL_MAX_DELAY);
}

/**
  * @brief  写命令到OLED
  * @param  Command 命令字节
  * @retval 无
  */
void OLED_WriteCommand(uint8_t Command)
{
    OLED_I2C_Write(&Command, 1, 1);
}

/**
  * @brief  写数据到OLED
  * @param  Data 数据字节
  * @retval 无
  */
void OLED_WriteData(uint8_t Data)
{
    OLED_I2C_Write(&Data, 1, 0);
}

/********************* OLED功能函数 *********************/

/**
  * @brief  设置光标位置
  * @param  Y 行位置 (0-7)
  * @param  X 列位置 (0-127)
  * @retval 无
  */
void OLED_SetCursor(uint8_t Y, uint8_t X)
{
    OLED_WriteCommand(0xB0 | Y);                    // 设置Y位置
    OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4));    // 设置X位置高4位
    OLED_WriteCommand(0x00 | (X & 0x0F));           // 设置X位置低4位
}

/**
  * @brief  OLED清屏
  * @param  无
  * @retval 无
  */
void OLED_Clear(void)
{
    uint8_t i, j;
    for (j = 0; j < 8; j++)
    {
        OLED_SetCursor(j, 0);
        for(i = 0; i < 128; i++)
        {
            OLED_WriteData(0x00);
        }
    }
}

/**
  * @brief  显示一个字符
  * @param  Line 行位置 (1-4)
  * @param  Column 列位置 (1-16)
  * @param  Char 要显示的字符
  * @retval 无
  */
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{
    uint8_t i;
    OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);
    for (i = 0; i < 8; i++)
    {
        OLED_WriteData(OLED_F8x16[Char - ' '][i]);
    }
    OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);
    for (i = 0; i < 8; i++)
    {
        OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);
    }
}

/**
  * @brief  显示字符串
  * @param  Line 起始行 (1-4)
  * @param  Column 起始列 (1-16)
  * @param  String 要显示的字符串
  * @retval 无
  */
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
    uint8_t i;
    for (i = 0; String[i] != '\0'; i++)
    {
        OLED_ShowChar(Line, Column + i, String[i]);
    }
}

/**
  * @brief  次方计算
  * @param  X 基数
  * @param  Y 指数
  * @retval X的Y次方
  */
uint32_t OLED_Pow(uint32_t X, uint32_t Y)
{
    uint32_t Result = 1;
    while (Y--)
    {
        Result *= X;
    }
    return Result;
}

/**
  * @brief  显示数字（十进制，正数）
  * @param  Line 行位置 (1-4)
  * @param  Column 列位置 (1-16)
  * @param  Number 要显示的数字
  * @param  Length 数字长度
  * @retval 无
  */
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
    uint8_t i;
    for (i = 0; i < Length; i++)
    {
        OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
    }
}

/**
  * @brief  显示数字（十进制，带符号）
  * @param  Line 行位置 (1-4)
  * @param  Column 列位置 (1-16)
  * @param  Number 要显示的数字
  * @param  Length 数字长度
  * @retval 无
  */
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
{
    uint8_t i;
    uint32_t Number1;
    if (Number >= 0)
    {
        OLED_ShowChar(Line, Column, '+');
        Number1 = Number;
    }
    else
    {
        OLED_ShowChar(Line, Column, '-');
        Number1 = -Number;
    }
    for (i = 0; i < Length; i++)
    {
        OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
    }
}

/**
  * @brief  显示数字（十六进制）
  * @param  Line 行位置 (1-4)
  * @param  Column 列位置 (1-16)
  * @param  Number 要显示的数字
  * @param  Length 数字长度
  * @retval 无
  */
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
    uint8_t i, SingleNumber;
    for (i = 0; i < Length; i++)
    {
        SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
        if (SingleNumber < 10)
        {
            OLED_ShowChar(Line, Column + i, SingleNumber + '0');
        }
        else
        {
            OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
        }
    }
}

/**
  * @brief  显示数字（二进制）
  * @param  Line 行位置 (1-4)
  * @param  Column 列位置 (1-16)
  * @param  Number 要显示的数字
  * @param  Length 数字长度
  * @retval 无
  */
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
    uint8_t i;
    for (i = 0; i < Length; i++)
    {
        OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
    }
}

/**
  * @brief  OLED初始化
  * @param  无
  * @retval 无
  */
void OLED_Init(void)
{
    HAL_Delay(100);  // 上电延时
    
    // 初始化序列
    OLED_WriteCommand(0xAE);    // 关闭显示
    
    OLED_WriteCommand(0xD5);    // 设置显示时钟分频比/振荡器频率
    OLED_WriteCommand(0x80);
    
    OLED_WriteCommand(0xA8);    // 设置多路复用率
    OLED_WriteCommand(0x3F);
    
    OLED_WriteCommand(0xD3);    // 设置显示偏移
    OLED_WriteCommand(0x00);
    
    OLED_WriteCommand(0x40);    // 设置显示开始行
    
    OLED_WriteCommand(0xA1);    // 设置左右方向，0xA1正常
    
    OLED_WriteCommand(0xC8);    // 设置上下方向，0xC8正常

    OLED_WriteCommand(0xDA);    // 设置COM引脚硬件配置
    OLED_WriteCommand(0x12);
    
    OLED_WriteCommand(0x81);    // 设置对比度控制
    OLED_WriteCommand(0xCF);

    OLED_WriteCommand(0xD9);    // 设置预充电周期
    OLED_WriteCommand(0xF1);

    OLED_WriteCommand(0xDB);    // 设置VCOMH取消选择级别
    OLED_WriteCommand(0x30);

    OLED_WriteCommand(0xA4);    // 设置整个显示打开/关闭

    OLED_WriteCommand(0xA6);    // 设置正常显示

    OLED_WriteCommand(0x8D);    // 设置充电泵
    OLED_WriteCommand(0x14);

    OLED_WriteCommand(0xAF);    // 开启显示
    
    OLED_Clear();               // 清屏
}

uint8_t a[][16] = {
	0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x3F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x80,0x40,0x20,0x10,0x0C,0x03,0x00,0x00,0x00,0x03,0x0C,0x10,0x20,0x40,0x80,0x00
};

// 人
void OLED_Test(uint8_t Line, uint8_t Column, char Char)
{
    uint8_t i;
	
    OLED_SetCursor((Line - 1) * 2, (Column - 1) * 16);
    for (i = 0; i < 16; ++i){
        OLED_WriteData(a[0][i]);
    }
    OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 16);
    for (i = 0; i < 16; ++i){
        OLED_WriteData(a[1][i]);
    }
}
